1. Field of the Invention
This invention relates to the field of computer programming languages. Specifically, this invention is a new and useful method, apparatus, and computer program product for implementing programming languages.
2. Background
A computer's central processing unit (CPU) is designed to execute computer instructions that perform operations on data-values. These data-values are generally stored in variables in memory and in the CPU's registers. Most general purpose computers have specialized instructions for operating on data-values of specific primitive types. These primitive data-value types include, without limitation, integer, byte, floating point and pointer types. Programming language compilers often allow these primitive types to be aggregated into structured and object types.
Compilers read an input program written in one language and generate an output program constructed to be executed according to an application binary interface (ABI). That is, the output program is usually a sequence of computer instructions that can be executed by the CPU. Programming languages and their compilers are designed to provide the programmer with flexibility in describing the operations that the computer executing the compiled program is to perform while balancing the need for generating an efficient output program. One language design trade-off is whether the type of the data-value is associated with the data-value itself or with the variable that stores the data-value.
Many compilers associate the data-value's type with the variable. These compilers perform static type checking at compile time to assure that only data-values of the appropriate type are stored into the variable. For example, only integer data-values are stored in an integer variable. The compiler will generate a compiler error if the programmer inadvertently instructs the program to store a non-integer data-value in the integer variable. The compiler can generate efficient code because the compiler knows the type of the data stored in a variable and only needs to generate the correct computer instruction to access the variable.
Other compilers associate data-value's type with the data-value itself. Thus, the data-value can be stored in a general purpose variable (a slot). The executing program first examines the data-value's type and then selects the appropriate computer instruction(s) to perform the operation on the data-value. This run-time type checking and operation dispatch imposes significant overhead in the resulting output program. The type of the data value is either stored in the same variable as the data-value (thus tagging the data-value and reducing the number of bits available in the variable for storing the data-value) or is stored in a type identifier associated with, but external to, the variable (an externally tagged data-value).
Object-oriented programming (OOP) languages associate an object's data with OOP methods for operating on that object's data. Usually, OOP objects are instantiated in a heap memory area and are based on class/maps that reference the programmed methods for the OOP object. Instantiated OOP objects are accessed through pointers and contain data (in instance variables) specific to that particular instantiated OOP object. Conceptually, an OOP object contains object-related information (such as the number of instance variables in the object), the instance variables, and addresses of called routines (OOP methods) that access and/or manipulate the contents of the instance variables in the object. However, because objects often share called routines and object-related information, this shared information is usually extracted into a class/map. Thus, the instantiated object simply contains its instance variables and a pointer to its class/map.
Pure object-oriented languages tend to have a data-value's type associated with the data-value. Traditional programming languages have data-value's type associated with the variable. These languages perform static type checking. Some object-oriented programming languages have taken a hybrid approach and associate primitive types with the variable (static type checking) and objects types with the data-value (dynamic type checking). These hybrid languages are efficient, but do not provide all of the advantages of a pure object-oriented implementation.
TABLE 1 ______________________________________ class truck { void CrashInto (truck n) {System.out.println("crunch");} class fueltruck extends trucks { void CrashInto (fueltruck n) {System.out.println("kaboom");} } public class test { public static void main(String[ ] args) { truck t1 = new fueltruck(); truck t2 = new fueltruck(); t1.CrashInto(t2); } } ______________________________________
One difficulty with hybrid OOP languages results from the characteristic that an instance of a subclass/map can be substituted for an instance of a superclass/map. Because a subclass/map can provide alternate OOP method implementations (alternate called routines), static type checking cannot, in general, determine if a single method will be invoked at runtime. At runtime the executing program must dynamically determine which called routine to invoke. For primitive types, the executing program determines which called routine to invoke based solely on the static types of the arguments and results passed to and from the called routine. The static rules that determine which called routine to invoke may conflict with the dynamic rules used for objects. For example, in the Java code fragment shown in Table 1, the Java compiler is unable to determine which CrashInto method the programmer intended to invoke and because variable t1 was typed as truck, the compiler uses truck's CrashInto method instead of fueltruck's CrashInto method. Thus, when the code in Table 1 is executed it prints out "crunch" instead of the "kaboom" intended by the programmer.
If Java would have associated the type with the data-value stored in the t1 variable instead of with the t1 variable itself, this code would have performed as the programmer intended because the type of the data-value stored in t1 would have been determined at run time instead of at compile time and the fueltruck's CrashInto method would have been called instead of the truck's CrashInto method.
Smalltalk, Self, Java and C++ are examples of OOP languages. Smalltalk was developed in the Learning Research Group at Xerox's Palo Alto Research Center (PARC) in the early 1970s. Self was developed by Randall B. Smith and David Ungar at Xerox's PARC in 1987. C++ was developed by Bjarne Stroustrup at the AT&T Bell Laboratories in 1983 as an extension of C. Java is an OOP language with elements from C and C++ and includes highly tuned libraries for the internet environment. It was developed at SUN Microsystems and released in 1995.
Further information about OOP concepts may be found in Not Just Java by Peter van der Linden, Sun Microsystems Press/Prentice Hall PTR Corp., Upper Saddle River, N.J., (1997), ISBN 0-13-864638-4, pages 136-149.
To summarize, existing hybrid-object-oriented programming languages, although efficient, are confusing to use because of the conflicts between the static and dynamic typing rules. On the other hand, pure-object-oriented programming languages that have internally tagged primitive types are inefficient.
It would be advantageous to implement a pure-object-oriented programming language that addresses the previously discussed problems with the prior art. In particular, it would be advantageous to develop a pure-object-oriented programming language environment that uses externally-tagged primitive types as primitive objects and that optimizes access to these objects.